package com.ltcode.auth.domain.model;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 认证令牌领域模型
 * 
 * @author ltcode
 * @since 2024-01-01
 */
@Data
public class AuthToken implements Serializable {
    
    private static final long serialVersionUID = 1L;

    /** 令牌唯一标识 */
    private String tokenId;

    /** 用户ID */
    private Long userId;

    /** 用户名 */
    private String username;

    /** 登录IP */
    private String loginIp;

    /** 登录时间 */
    private Date loginTime;

    /** 过期时间 */
    private Date expireTime;

    /** 令牌类型 */
    private TokenType tokenType;

    /** 令牌状态 */
    private TokenStatus status;

    /** 设备信息 */
    private String deviceInfo;

    /** 用户代理 */
    private String userAgent;

    /**
     * 令牌类型枚举
     */
    public enum TokenType {
        ACCESS_TOKEN("access_token", "访问令牌"),
        REFRESH_TOKEN("refresh_token", "刷新令牌");

        private final String code;
        private final String description;

        TokenType(String code, String description) {
            this.code = code;
            this.description = description;
        }

        public String getCode() {
            return code;
        }

        public String getDescription() {
            return description;
        }
    }

    /**
     * 令牌状态枚举
     */
    public enum TokenStatus {
        ACTIVE("active", "有效"),
        EXPIRED("expired", "已过期"),
        REVOKED("revoked", "已撤销");

        private final String code;
        private final String description;

        TokenStatus(String code, String description) {
            this.code = code;
            this.description = description;
        }

        public String getCode() {
            return code;
        }

        public String getDescription() {
            return description;
        }
    }

    /**
     * 检查令牌是否有效
     */
    public boolean isValid() {
        return TokenStatus.ACTIVE.equals(status) && !isExpired();
    }

    /**
     * 检查令牌是否过期
     */
    public boolean isExpired() {
        return expireTime != null && expireTime.before(new Date());
    }

    /**
     * 检查是否需要刷新
     * 当剩余时间少于总时间的1/3时需要刷新
     */
    public boolean needRefresh(long totalExpireMinutes) {
        if (expireTime == null) {
            return false;
        }
        
        long currentTime = System.currentTimeMillis();
        long expireTimeMillis = expireTime.getTime();
        long remainingTime = expireTimeMillis - currentTime;
        long totalTime = totalExpireMinutes * 60 * 1000; // 转换为毫秒
        
        return remainingTime < totalTime / 3;
    }

    /**
     * 刷新令牌过期时间
     */
    public void refreshExpireTime(long expireMinutes) {
        this.expireTime = new Date(System.currentTimeMillis() + expireMinutes * 60 * 1000);
    }

    /**
     * 撤销令牌
     */
    public void revoke() {
        this.status = TokenStatus.REVOKED;
    }

    /**
     * 标记为过期
     */
    public void markExpired() {
        this.status = TokenStatus.EXPIRED;
    }

    /**
     * 创建访问令牌
     */
    public static AuthToken createAccessToken(String tokenId, Long userId, String username, 
                                            String loginIp, long expireMinutes) {
        AuthToken token = new AuthToken();
        token.setTokenId(tokenId);
        token.setUserId(userId);
        token.setUsername(username);
        token.setLoginIp(loginIp);
        token.setLoginTime(new Date());
        token.setExpireTime(new Date(System.currentTimeMillis() + expireMinutes * 60 * 1000));
        token.setTokenType(TokenType.ACCESS_TOKEN);
        token.setStatus(TokenStatus.ACTIVE);
        return token;
    }

    /**
     * 创建刷新令牌
     */
    public static AuthToken createRefreshToken(String tokenId, Long userId, String username, 
                                             String loginIp, long expireMinutes) {
        AuthToken token = new AuthToken();
        token.setTokenId(tokenId);
        token.setUserId(userId);
        token.setUsername(username);
        token.setLoginIp(loginIp);
        token.setLoginTime(new Date());
        token.setExpireTime(new Date(System.currentTimeMillis() + expireMinutes * 60 * 1000));
        token.setTokenType(TokenType.REFRESH_TOKEN);
        token.setStatus(TokenStatus.ACTIVE);
        return token;
    }
}
